// D3D9VertexDeclaration.cpp

#include "stdafx.h"

#include "D3D9VertexDeclaration.h"

//////////////////////////////////////////////////////////////////////////
CD3D9VertexDeclaration::CD3D9VertexDeclaration(LPDIRECT3DDEVICE9 device) :
m_pDevice(device), m_bNeedsRebuild(false), m_pDecl(NULL)
{
}

CD3D9VertexDeclaration::~CD3D9VertexDeclaration()
{
	m_pDevice = NULL;
}

//////////////////////////////////////////////////////////////////////////
void CD3D9VertexDeclaration::AddElement(WORD Stream, WORD Offset, BYTE Type, BYTE Method, BYTE Usage, BYTE UsageIndex)
{
	m_bNeedsRebuild = true;

	D3DVERTEXELEMENT9 elem;

	elem.Stream = Stream;
	elem.Offset = Offset;
	elem.Type = Type;
	elem.Method = Method;
	elem.Usage = Usage;
	elem.UsageIndex = UsageIndex;
	m_ElementList.push_back(elem);
}

void CD3D9VertexDeclaration::InsertElement(WORD Stream, WORD Offset, BYTE Type, BYTE Method, BYTE Usage, BYTE UsageIndex, unsigned short usIndex)
{
	m_bNeedsRebuild = true;
	if (usIndex >= m_ElementList.size())
	{
		AddElement(Stream, Offset, Type, Method, Usage, UsageIndex);
		return;
	}

	D3DVERTEXELEMENT9 elem;

	elem.Stream = Stream;
	elem.Offset = Offset;
	elem.Type = Type;
	elem.Method = Method;
	elem.Usage = Usage;
	elem.UsageIndex = UsageIndex;

	std::list<D3DVERTEXELEMENT9>::iterator iter(m_ElementList.begin());
	for (unsigned short i = 0; i < usIndex; ++i)
	{
		++iter;
	}

	m_ElementList.insert(iter, elem);
}

LPDIRECT3DVERTEXDECLARATION9 CD3D9VertexDeclaration::getD3DVertexDeclaration(void)
{
	if (m_bNeedsRebuild)
	{
		if (m_pDecl) {
			m_pDecl->Release();
			m_pDecl = NULL;
		}

		D3DVERTEXELEMENT9* pd3dElems = new D3DVERTEXELEMENT9[m_ElementList.size() + 1];
		unsigned short usIndex = 0;
		std::list<D3DVERTEXELEMENT9>::const_iterator iter(m_ElementList.begin());
		for (; iter != m_ElementList.end(); ++iter, ++usIndex)
		{
			const D3DVERTEXELEMENT9& info = *iter;
			memcpy(pd3dElems + usIndex, &info, sizeof(D3DVERTEXELEMENT9));
		}

		// Add terminator
		pd3dElems[usIndex].Stream = 0xff;
		pd3dElems[usIndex].Offset = 0;
		pd3dElems[usIndex].Type = D3DDECLTYPE_UNUSED;
		pd3dElems[usIndex].Method = 0;
		pd3dElems[usIndex].Usage = 0;
		pd3dElems[usIndex].UsageIndex = 0;

		HRESULT hr;
		hr = m_pDevice->CreateVertexDeclaration(pd3dElems, &m_pDecl);
		if (FAILED(hr))
		{
			exit(-1);
			return NULL;
		}

		delete [] pd3dElems;
		m_bNeedsRebuild = false;
	}

	return m_pDecl;
}